/**
 *  julive
 *
 *  Create by songli on 2021/07/07
 *  Copyright © 2021 居理买房网. All rights reserved.
 */

package server

import (
	"context"
	"fmt"
	"net"
	"net/http"
	_ "net/http/pprof"
	"runtime"
	"strconv"
	"sync"

	"github.com/grpc-ecosystem/go-grpc-middleware/logging/zap/ctxzap"
	gw_runtime "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
	"github.com/spf13/viper"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"google.golang.org/grpc"

	"git.julive.com/julive/shorturl/client"
	"git.julive.com/julive/shorturl/server/proto/shorturl"
	"git.julive.com/julive/shorturl/server/service"
	"git.julive.com/micro/pkg/grpcx"
	"git.julive.com/micro/pkg/helper"
	"git.julive.com/micro/pkg/logx"
	"git.julive.com/micro/pkg/tracing"
)

func Serve() (err error) {
	// 初始化日志
	logPath := viper.GetString("log.path")
	logLevel := viper.GetInt("log.level")
	logAge := viper.GetInt("log.age")
	logSize := viper.GetInt("log.size")
	logBackup := viper.GetInt("log.backup")
	logCompress := viper.GetBool("log.compress")
	logFormat := viper.GetString("log.format")

	zapLogger := logx.NewLogger(logPath, zapcore.Level(logLevel), logSize, logBackup, logAge, logCompress, logFormat, zap.Fields(zap.String("project", "julive"), zap.String("service", "shorturl")))
	ctx := ctxzap.ToContext(context.Background(), zapLogger)

	// 初始化上下文
	ctx, cancel := context.WithCancel(ctx)
	defer cancel()

	traceName := viper.GetString("tracing.name.server")
	// 初始化调用链追踪
	tracer, closer, err := tracing.InitTracer(traceName)
	if err != nil {
		return err
	}
	defer closer.Close()

	grpcServer := grpcx.NewGrpcServer(zapLogger, tracer)
	shorturl.RegisterShorturlServiceServer(grpcServer, service.NewShorturlService())

	gRPCPort := viper.GetInt("server.port.grpc")

	listener, err := net.Listen("tcp", fmt.Sprintf(":%d", gRPCPort))
	if err != nil {
		return err
	}

	var wg sync.WaitGroup
	wg.Add(1)

	// 启动gGRC监听
	go func() {
		defer wg.Done()

		zapLogger.Info("GrpcServer is running at port:" + strconv.Itoa(gRPCPort))

		grpcServer.Serve(listener)
	}()

	defer client.Close()

	HttpPort := viper.GetInt("server.port.http")
	httpServer, err := NewHttpServer(ctx, gRPCPort, HttpPort)
	if err != nil {
		return err
	}

	go func() {
		defer wg.Done()

		zapLogger.Info("HttpServer is running at port:" + strconv.Itoa(HttpPort))
		if err := httpServer.ListenAndServe(); err != nil {
			zapLogger.Error("HttpServer running error", zap.Error(err))
		}
	}()

	// 退出时关闭gRPC、HTTP
	defer func() {
		grpcServer.GracefulStop()
		httpServer.Shutdown(ctx)
	}()

	wg.Wait()

	return nil
}

// 创建GrpcServer
// @ctx 上下文
func NewHttpServer(ctx context.Context, gRPCPort, HttpPort int) (*http.Server, error) {
	rate := viper.GetInt("server.profile.rate")
	runtime.SetBlockProfileRate(rate)

	// 注册gRPC-Gateway
	localGrpc := fmt.Sprintf(":%d", gRPCPort)
	mux := gw_runtime.NewServeMux(gw_runtime.WithForwardResponseOption(helper.ResponseHeaderMatcher)) //gw_runtime.WithMetadata(middleware.InitMeta))
	opts := []grpc.DialOption{grpc.WithInsecure()}
	err := shorturl.RegisterShorturlServiceHandlerFromEndpoint(ctx, mux, localGrpc, opts)
	if err != nil {
		return nil, err
	}

	router := http.DefaultServeMux
	router.Handle("/", mux)

	httpServer := &http.Server{
		Addr:    fmt.Sprintf(":%d", HttpPort),
		Handler: router,
	}

	return httpServer, nil
}
